#pragma once

#include "funpl.h"
#include "ast_statements.h"
#include <vector>

namespace funpl
{

namespace ast
{

/// Character literal node.
struct char_literal : public expression
{
	util::const_char_range literal;

	/// Constructor.
	char_literal(node *parent = nullptr,
		const util::const_char_range &literal = util::empty_const_char_range())
			: expression(node_type::char_literal, parent),
			literal(literal) { }
};

/// String literal node.
struct string_literal : public expression
{
	util::const_char_range literal;

	/// Constructor.
	string_literal(node *parent = nullptr,
		const util::const_char_range &literal = util::empty_const_char_range())
			: expression(node_type::string_literal, parent),
			literal(literal) { }
};

namespace num_literal_type
{
	enum t
	{
		byte,
		short_,
		int_,
		long_,
		float_,
		double_
	};
};

/// Numeric literal node.
struct num_literal : public expression
{
	num_literal_type::t type;
	bool unsigned_;

protected:
	/// Constructor.
	num_literal(node_type::t type, node *parent = nullptr)
		: expression(type, parent),
		type(num_literal_type::int_),
		unsigned_(false) { }
};

template <class Value> struct literal_from_type;
template <> struct literal_from_type<double> { static const node_type::t value = node_type::float_literal; };
template <> struct literal_from_type<long> { static const node_type::t value = node_type::int_literal; };
template <> struct literal_from_type<unsigned long> { static const node_type::t value = node_type::uint_literal; };
template <> struct literal_from_type<long long> { static const node_type::t value = node_type::long_literal; };
template <> struct literal_from_type<unsigned long long> { static const node_type::t value = node_type::ulong_literal; };

/// Double literal node.
template <class Value>
struct typed_num_literal : public num_literal
{
	typedef Value value_type;
	value_type value;

	/// Constructor.
	typed_num_literal(node *parent = nullptr)
		: num_literal(literal_from_type<value_type>::value, parent),
		value() { }
};

} // namespace

} // namespace